/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/**
 * Software License, Version 1.0
 *
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 *
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For
 * further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and
 * wherever such third-party acknowledgments normally appear.
 *
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering,
 * shall not be used to endorse or promote products derived from this software
 * without prior written permission from Indiana University.  For written
 * permission, please contact the Advanced Research and Technology Institute
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering,
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 *
 *
 * Indiana University provides no reassurances that the source code provided
 * does not infringe the patent or any other intellectual property rights of
 * any other entity.  Indiana University disclaims any liability to any
 * recipient for claims brought by any other entity based on infringement of
 * intellectual property rights or otherwise.
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.sync;

import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * This class provides some methods to make UDP connection, send/receive NTP
 * packets
 *
 * @author Hasan Bulut - hbulut@indiana.edu
 */
public class SyncConnection {
    //~ Static fields/initializers -----------------------------------------------

    public static final int defaultNtpPort = 123;
    //~ Instance fields ----------------------------------------------------------
    private DatagramSocket syncSocket;
    private InetAddress syncServer;
    private int syncPort;
    private int timeout = 500;
    SyncInfo syncInfo;
    //~ Constructors -------------------------------------------------------------

    /**
     * Generates a UDP connection and sets timeout to the socket
     *
     * @param iaddr InetAddress - InetAddress of the server
     * @param iport int - port number of the server
     * @throws SocketException - SocketException is thrown in case of failure
     */
    public SyncConnection(InetAddress iaddr, int iport) throws SocketException {
        syncServer = iaddr;
        syncPort = iport;
        syncSocket = new DatagramSocket();
        syncSocket.setSoTimeout(timeout);

        syncInfo = new SyncInfo();
    }

    /**
     * Generates a UDP connection and sets the timeout to the default timeout value.
     * @param iaddr InetAddress - InetAddress of the server
     * @throws SocketException - SocketException is thrown in case of failure
     */
    public SyncConnection(InetAddress iaddr) throws SocketException {
        syncServer = iaddr;
        syncPort = defaultNtpPort;
        syncSocket = new DatagramSocket();
        syncSocket.setSoTimeout(timeout);

        syncInfo = new SyncInfo();
    }

    //~ Methods ------------------------------------------------------------------
    /**
     * Sets buffer entries from start to end-1 with the given data array
     *
     * @param start int - start value
     * @param end int - end value
     * @param tbuffer byte[] - buffer
     * @param data byte[] - data array to be copied
     */
    public void setBuffer(int start, int end, byte[] tbuffer, byte[] data) {
        if (tbuffer.length >= end) {
            for (int i = start; i < end; i++) {
                tbuffer[i] = data[i - start];
            }
        }
    }

    /**
     * Exchanges SyncDatagramPacket with the server and generates SyncInfo object.
     * @return SyncInfo - SyncInfo object obtained from NTPDatagramPacket
     * @throws IOException - IOException is thrown in case of socket timeout or connection failure
     */
    public SyncInfo getInfo() throws IOException {
        this.syncInfo = new SyncInfo();
        SyncDatagramPacket dpReceive = new SyncDatagramPacket();
        SyncDatagramPacket dpSend = new SyncDatagramPacket(syncServer, syncPort);
        send(dpSend);
        receive(dpReceive);
        syncInfo.setReception(new SyncTimestamp().getTimeInMicroSeconds());
        syncInfo.setReceive(dpReceive.getTimeStamp().getTimeInMicroSeconds());
        receive(dpReceive);
        syncInfo.setTransmit(dpReceive.getTimeStamp().getTimeInMicroSeconds());

        return this.syncInfo;
    }

    /**
     * This method is intended to be used with ClientDiscrepancy class. Please do
     * not use for other purposes. Returns SyncInfo.
     * @return SyncInfo
     *
     * @throws IOException
    /
    public SyncInfo getTSInfo() throws IOException {
    SyncInfo      syncInfo    = new SyncInfo();
    SyncTimestamp transmitTS = new SyncTimestamp();
    long         offset1    = tsi.getOffset();
    transmitTS.setTimestamp(new Date((new Date()).getTime() + offset1));
    SyncDatagramPacket dpReceive = new SyncDatagramPacket();
    SyncDatagramPacket dpSend = new SyncDatagramPacket(syncServer, syncPort);
    setBuffer(NtpOffset.offTransmitTimestamp, NtpOffset.NTPDataLength,
    dpSend.getDatagramPacket().getData(),
    transmitTS.getTimestampData());
    send(dpSend);
    receiveTS(dpReceive, offset1);
    syncInfo = dpReceive.getInfo();
    return syncInfo;
    }

    /**
     * Sets the timeout of the associated connection.
     * @param timeout int - value of the timeout
     * @throws SocketException - SocketException is thrown in case of connection failure
     */
    public void setTimeout(int timeout) throws SocketException {
        this.timeout = timeout;
        syncSocket.setSoTimeout(timeout);
    }

    /**
     * Gets the timeout of the connection. The default timeout
     * is 500 ms.
     * @return int - timeout value
     */
    public int getTimeout() {
        return timeout;
    }

    /**
     * Closes the connection.
     */
    public void close() {
        syncSocket.close();
    }

    /**
     * Waits for a reply from the server.
     * @param syncDatagramPacket SyncDatagramPacket - SyncDatagramPacket that will be
     * set to the SyncDatagramPacket received from the server.
     * @throws IOException - IOException is thrown in case of socket timeout or connection failure
     */
    public void receive(SyncDatagramPacket syncDatagramPacket)
            throws IOException {
        syncSocket.receive(syncDatagramPacket.getDatagramPacket());
        //syncDatagramPacket.setReceptionTimeStamp(new SyncTimestamp());
    }

    /**
     * This method is intended to be used with ClientDiscrepancy class. Please do
     * not use for other purposes. Receives SyncDatagramPacket and timestamps it
     * with the adjusted time value.
     * @param syncDatagramPacket
     * @param offset11 long - offset
     *
     * @throws IOException
    /modificado 11/10/2005
    public void receiveTS(SyncDatagramPacket syncDatagramPacket, long offset11)
    throws IOException {
    syncSocket.receive(syncDatagramPacket.getDatagramPacket());
    SyncTimestamp ts = new SyncTimestamp();
    ts.setTimestamp(SyncTimestamp.clock.getTimeMicroseconds() +
    offset11);
    //syncDatagramPacket.setReceptionTimeStamp(ts);
    }

    /**
     * Sends SyncDatagramPacket to the server.
     * @param syncDatagramPacket SyncDatagramPacket - SyncDatagramPacket that will be
     * sent to the server.
     * @throws IOException - IOException is thrown in case of connection failure
     */
    public void send(SyncDatagramPacket syncDatagramPacket)
            throws IOException {
        syncSocket.send(syncDatagramPacket.getDatagramPacket());
        syncInfo.setOriginate(new SyncTimestamp().getTimeInMicroSeconds());
        //System.out.println("Fim: "+cgl.narada.service.timer.HRClock.getClock().getTimeMicroseconds());
    }
}
